package com.lh.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
@Slf4j
public class DateTimeUtil {
	/**
	 * 缺省的日期显示格式： yyyy-MM-dd
	 */
	public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";

	/**
	 * 缺省的日期显示格式： yyyyMMdd
	 */
	public static final String DEFAULT_DATE_FORMAT_B = "yyyyMMdd";

	public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
	public static final String DEFAULT_TIME_FORMAT_B = "HHmmss";

	/**
	 * 缺省的日期时间显示格式：yyyy-MM-dd HH:mm:ss
	 */
	public static final String DEFAULT_DATETIME_FORMAT = DEFAULT_DATE_FORMAT
			+ " " + DEFAULT_TIME_FORMAT;

	public static final String DEFAULT_DATETIME_FORMAT_B = DEFAULT_DATE_FORMAT_B
			+ DEFAULT_TIME_FORMAT_B;

	/**
	 * 私有构造方法，禁止对该类进行实例化
	 */
	private DateTimeUtil() {
	}

	/**
	 * 得到系统当前日期时间
	 *
	 * @return 当前日期时间
	 */
	public static Date getNow() {
		return Calendar.getInstance().getTime();
	}

	/**
	 * 得到用缺省方式格式化的当前日期
	 *
	 * @return 当前日期
	 */
	public static String getDate() {
		return getDateTime(DEFAULT_DATE_FORMAT);
	}

	/**
	 * 得到用缺省方式格式化的当前日期及时间
	 *
	 * @return 当前日期及时间
	 */
	public static String getDateTime() {
		return getDateTime(DEFAULT_DATETIME_FORMAT);
	}

	/**
	 * 得到系统当前日期及时间，并用指定的方式格式化
	 *
	 * @param pattern
	 *            显示格式
	 * @return 当前日期及时间
	 */
	public static String getDateTime(String pattern) {
		Date datetime = Calendar.getInstance().getTime();
		return getDateTime(datetime, pattern);
	}

    /**
	 * 得到用指定方式格式化的日期
	 *
	 * @param date
	 *            需要进行格式化的日期
	 * @param pattern
	 *            显示格式
	 * @return 日期时间字符串
	 */
	public static String getDateTime(Date date, String pattern) {
		if (null == pattern || "".equals(pattern)) {
			pattern = DEFAULT_DATETIME_FORMAT;
		}
		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
		return dateFormat.format(date);
	}

	/**
	 * 得到当前年份
	 *
	 * @return 当前年份
	 */
	public static int getCurrentYear() {
		return LocalDate.now().getYear();
	}

	public static int getCurrentYear(Date date) {
		return DateToLocalDate(date).getYear();
	}
	/**
	 * 得到当前月份
	 *
	 * @return 当前月份
	 */
	public static int getCurrentMonth() {
		return LocalDate.now().getMonthValue();
	}

	public static int getCurrentMonth(Date date) {
		return DateToLocalDate(date).getMonthValue();
	}

	/**
	 * 获取当前时间在第几季
	 *
	 * @return 当前月份
	 */
	public static int getCurrentSeason() {
		int monthValue = LocalDate.now().getMonthValue();
		if(monthValue==1||monthValue==2||monthValue==3){
			return 1;
		} else if(monthValue==4||monthValue==5||monthValue==6){
			return 2;
		}else if(monthValue==7||monthValue==8||monthValue==9){
			return 3;
		}else{
			return 4;
		}
	}

	public static int getCurrentSeason(Date date) {
		int monthValue = DateToLocalDate(date).getMonthValue();
		if(monthValue==1||monthValue==2||monthValue==3){
			return 1;
		} else if(monthValue==4||monthValue==5||monthValue==6){
			return 2;
		}else if(monthValue==7||monthValue==8||monthValue==9){
			return 3;
		}else{
			return 4;
		}
	}
	/**
	 * 得到当前日
	 *
	 * @return 当前日
	 */
	public static int getCurrentDay() {
		return Calendar.getInstance().get(Calendar.DATE);
	}

	/**
	 * 对日期的【秒】进行加/减
	 *
	 * @param date 日期
	 * @param seconds 秒数，负数为减
	 * @return 加/减几秒后的日期
	 */
	public static Date addDateSeconds(Date date, int seconds) {
		DateTime dateTime = new DateTime(date);
		return dateTime.plusSeconds(seconds).toDate();
	}

	/**
	 * 对日期的【分钟】进行加/减
	 *
	 * @param date 日期
	 * @param minutes 分钟数，负数为减
	 * @return 加/减几分钟后的日期
	 */
	public static Date addDateMinutes(Date date, int minutes) {
		DateTime dateTime = new DateTime(date);
		return dateTime.plusMinutes(minutes).toDate();
	}

	/**
	 * 对日期的【小时】进行加/减
	 *
	 * @param date 日期
	 * @param hours 小时数，负数为减
	 * @return 加/减几小时后的日期
	 */
	public static Date addDateHours(Date date, int hours) {
		DateTime dateTime = new DateTime(date);
		return dateTime.plusHours(hours).toDate();
	}

	/**
	 * 取得当前日期以后若干天的日期。如果要得到以前的日期，参数用负数。 例如要得到上星期同一天的日期，参数则为-7
	 *
	 * @param days
	 *            增加的日期数
	 * @return 增加以后的日期
	 */
	public static Date addDays(int days) {
		return add(getNow(), days, Calendar.DATE);
	}

	/**
	 * 取得指定日期以后若干天的日期。如果要得到以前的日期，参数用负数。
	 *
	 * @param date
	 *            基准日期
	 * @param days
	 *            增加的日期数
	 * @return 增加以后的日期
	 */
	public static Date addDays(Date date, int days) {
		return add(date, days, Calendar.DATE);
	}

	/**
	 * 取得当前日期以后某月的日期。如果要得到以前月份的日期，参数用负数。
	 *
	 * @param months
	 *            增加的月份数
	 * @return 增加以后的日期
	 */
	public static Date addMonths(int months) {
		return add(getNow(), months, Calendar.MONTH);
	}

	/**
	 * 取得指定日期以后某月的日期。如果要得到以前月份的日期，参数用负数。 注意，可能不是同一日子，例如2003-1-31加上一个月是2003-2-28
	 *
	 * @param date
	 *            基准日期
	 * @param months
	 *            增加的月份数
	 *
	 * @return 增加以后的日期
	 */
	public static Date addMonths(Date date, int months) {
		return add(date, months, Calendar.MONTH);
	}

	/**
	 * 内部方法。为指定日期增加相应的天数或月数
	 *
	 * @param date
	 *            基准日期
	 * @param amount
	 *            增加的数量
	 * @param field
	 *            增加的单位，年，月或者日
	 * @return 增加以后的日期
	 */
	private static Date add(Date date, int amount, int field) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(field, amount);
		return calendar.getTime();
	}

	/**
	 * 计算两个日期相差天数。 用第一个日期减去第二个。如果前一个日期小于后一个日期，则返回负数
	 *
	 * @param one
	 *            第一个日期数，作为基准
	 * @param two
	 *            第二个日期数，作为比较
	 * @return 两个日期相差天数
	 */
	public static long diffDays(Date one, Date two) {
		return (one.getTime() - two.getTime()) / (24 * 60 * 60 * 1000);
	}

	/**
	 * 计算两个日期相差月份数 如果前一个日期小于后一个日期，则返回负数
	 *
	 * @param one
	 *            第一个日期数，作为基准
	 * @param two
	 *            第二个日期数，作为比较
	 * @return 两个日期相差月份数
	 */
	public static int diffMonths(Date one, Date two) {
		Calendar calendar = Calendar.getInstance();
		// 得到第一个日期的年分和月份数
		calendar.setTime(one);
		int yearOne = calendar.get(Calendar.YEAR);
		int monthOne = calendar.get(Calendar.MONDAY);
		// 得到第二个日期的年份和月份
		calendar.setTime(two);
		int yearTwo = calendar.get(Calendar.YEAR);
		int monthTwo = calendar.get(Calendar.MONDAY);
		return (yearOne - yearTwo) * 12 + (monthOne - monthTwo);
	}

	/**
	 * 将一个字符串用给定的格式转换为日期类型。<br>
	 * 注意：如果返回null，则表示解析失败
	 *
	 * @param datestr
	 *            需要解析的日期字符串
	 * @param pattern
	 *            日期字符串的格式，默认为“yyyy-MM-dd”的形式
	 * @return 解析后的日期
	 */
	public static Date parse(String datestr, String pattern) {
		Date date = null;
		if (null == pattern || "".equals(pattern)) {
			pattern = DEFAULT_DATE_FORMAT;
		}
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
			date = dateFormat.parse(datestr);
		} catch (ParseException e) {
		}
		return date;
	}

	/**
	 * 将一个字符串用给定的格式转换为日期类型。<br>
	 * 注意：如果返回null，则表示解析失败
	 *
	 * @param datestr
	 *            需要解析的日期字符串
	 * @return 解析后的日期
	 */
	public static Date parse(String datestr) {
		return parse(datestr,DEFAULT_DATETIME_FORMAT);
	}


	/**
	 * 返回本月的最后一天
	 *
	 * @return 本月最后一天的日期
	 */
	public static Date getMonthLastDay() {
		return getMonthLastDay(getNow());
	}

	/**
	 * 返回给定日期中的月份中的最后一天
	 *
	 * @param date
	 *            基准日期
	 * @return 该月最后一天的日期
	 */
	public static Date getMonthLastDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		// 将日期设置为下一月第一天
		calendar.set(calendar.get(Calendar.YEAR),
				calendar.get(Calendar.MONTH) + 1, 1);
		// 减去1天，得到的即本月的最后一天
		calendar.add(Calendar.DATE, -1);
		System.out.println(getDateStr(calendar.getTime(),DEFAULT_DATE_FORMAT)+" 23:59:59");
		return  parse(getDateStr(calendar.getTime(),DEFAULT_DATE_FORMAT)+" 23:59:59",DEFAULT_DATETIME_FORMAT);
//		return  calendar.getTime();
	}

	/**
	 *
	 * @Title: getTimeMillisecond
	 * @Description:把指定时间转换为毫秒 TODO(这里用一句话描述这个方法的作用)
	 * @param @param dateStr
	 * @param @return 设定文件
	 * @return long 返回类型
	 * @throws
	 */
	public static long getTimeMillisecond(Date date) {
		Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getTimeInMillis();
	}

	/**
	 *
	 * @Title: getDateStr
	 * @Description:把指定时间转换为指定的字符串 TODO(这里用一句话描述这个方法的作用)
	 * @param @param date
	 * @param @param pattern
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getDateStr(Date date, String pattern) {
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		String str = sdf.format(date);
		return str;
	}

	/**
	 *
	 * @Title: getDateStrByMill
	 * @Description:毫秒转换指定日期 TODO(这里用一句话描述这个方法的作用)
	 * @param @param millis
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getDateStrByMill(long millis, String pattern) {
		DateFormat formatter = new SimpleDateFormat(pattern);
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(millis);
		Date date = c.getTime();
		return formatter.format(date);
	}

	/**
	 *
	 * @Title: getDateAddSecond
	 * @Description:指定时间加多少秒 TODO(这里用一句话描述这个方法的作用)
	 * @param @param second
	 * @param @return 设定文件
	 * @return Date 返回类型
	 * @throws
	 */
	public static Date getDateAddSecond(Date date, int second) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.SECOND, second);
		return calendar.getTime();
	}

	/**
	 * @Title: getTimeStamp
	 * @Description: TODO(这里用一句话描述这个方法的作用)
	 * @param @param timeStamp
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getTimeStamp(long timeStamp, String dateFormate) {
	    SimpleDateFormat sim=new SimpleDateFormat(dateFormate);
        Date date2 = new Date();
        date2.setTime(timeStamp);
        return sim.format(date2);
	}

	/**
	 *
	 * @Title: getDate
	 * @Description:把字符串转换成指定的日期格式 TODO(这里用一句话描述这个方法的作用)
	 * @param @param str
	 * @param @param dateFormate
	 * @param @return 设定文件
	 * @return Date 返回类型
	 * @throws
	 */
	public static Date getDateFormate(String str, String dateFormate) {
		Date d = null;
		try {
			d = new SimpleDateFormat(dateFormate).parse(str);
		} catch (Exception e) {
			log.error("errorInfo:{}",e);
		}
		return d;
	}

	/**
	 * 获取传入时间的0点
	 * @param datetime
	 * @return
	 */
	public static Date dateZero(Date datetime){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(datetime);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
		Date zero = calendar.getTime();

		return zero;
	}

	/**
	 * 获取当天的0点
	 * @return
	 */
	public static Date dateZero(){
		return dateZero(new Date());
	}

	/**
	 * 获取传入时间的23点
	 * @param datetime
	 * @return
	 */
	public static Date date23(Date datetime){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(datetime);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date zero = calendar.getTime();

		return zero;
	}

	/**
	 * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致

	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return boolean
	 * @author wuxin
	 */
	public static boolean isEffectiveDate( Date startTime, Date endTime) {

		Calendar date = Calendar.getInstance();
		date.setTime(new Date());

		Calendar begin = Calendar.getInstance();
		begin.setTime(startTime);

		Calendar end = Calendar.getInstance();
		end.setTime(endTime);

		if (date.after(begin) && date.before(end)) {
			return true;
		} else {
			return false;
		}
	}

	public static String toDayString(String date) {

		return  toDayString(getDateFormate(date,DEFAULT_DATE_FORMAT));

	}
	public static String  toDayString(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);

		int year = c.get(Calendar.YEAR);
		int month = c.get(Calendar.MONTH) + 1;
		int day = c.get(Calendar.DAY_OF_MONTH);

		return year + "年" + month + "月" + day + "日";
	}

	//
	/**
	 * 将java.util.Date 转换成 java.time.LocalDate
	 * @param date
	 * @return
	 */
	public static LocalDate DateToLocalDate(Date date) {
		Instant instant = date.toInstant();
		ZoneId zone = ZoneId.systemDefault();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
		return localDateTime.toLocalDate();
	}

	/**
	 * 获取当前年份的自然周
	 * @param
	 * @return
	 */
	public static int getWeeks() {
		LocalDate localDate = LocalDate.now();
		WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,4);
		int weeks = localDate.get(weekFields.weekOfWeekBasedYear());
		return weeks;
	}

	/**
	 * 获取传入时间的当前年份的自然周
	 * @param
	 * @return
	 */
	public static int getWeeks(Date date) {
		LocalDate localDate = DateToLocalDate(date);
		WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,4);
		int weeks = localDate.get(weekFields.weekOfWeekBasedYear());
		return weeks;
	}

	/**
	 * 根据日期判断本月有多少天
	 * @param date
	 * @return
	 */
	public static Long dayByMonth(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int year = cal.get(Calendar.YEAR);
		int month = cal.get(Calendar.MONTH) + 1;

		switch (month) {
			case 1:
			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
			case 12:
				return 31L;
			case 4:
			case 6:
			case 9:
			case 11:
				return 30L;
			//对于2月份需要判断是否为闰年
			case 2:
				if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
					return 29L;
				} else {
					return 28L;
				}

			default:
				return 0L;
		}
	}

	/**
	 * 根据当前时间获取第几天
	 * @param date
	 * @param days
	 * @return
	 */
	public static Date getDayOfMonth(Date date,int days){
		Calendar cal_1=Calendar.getInstance();
		cal_1.setTime(date);
		cal_1.add(Calendar.MONTH, 0);
		cal_1.set(Calendar.DAY_OF_MONTH,days);
		return cal_1.getTime();
	}

	/**
	 * 获取明天日00:00:00
	 *
	 * @return 时间
	 */
	public static Date getTomorrow() {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE,1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND,0);
		return calendar.getTime();
	}

	/**
     * 距离明天凌晨零点的秒数
	 * @return
     */
	public static long getTillTomorrowTime(){

		return (getTomorrow().getTime()-System.currentTimeMillis())/1000;
	}

	/**
	 * CST时间格式转换成date类型
	 * @param cstDataStr
	 * @return
	 */
	public static Date parseDate(String cstDataStr) throws Exception {
		SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
		Date date = null;
		try {
			date = format.parse(cstDataStr);
		} catch (ParseException e) {
			format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
			date = format.parse(cstDataStr);
		}
		return date;
	}


	/**
	 * 根据周数，获取开始日期、结束日期
	 * @param week  周期  0本周，-1上周，-2上上周，1下周，2下下周
	 * @return  返回date[0]开始日期、date[1]结束日期
	 */
	public static Date[] getWeekStartAndEnd(int week) {
		DateTime dateTime = new DateTime();
		org.joda.time.LocalDate date = new org.joda.time.LocalDate(dateTime.plusWeeks(week));

		date = date.dayOfWeek().withMinimumValue();
		Date beginDate = date.toDate();
		Date endDate = date.plusDays(6).toDate();
		return new Date[]{beginDate, endDate};
	}


	/**
	 * 对日期的【周】进行加/减
	 *
	 * @param date 日期
	 * @param weeks 周数，负数为减
	 * @return 加/减几周后的日期
	 */
	public static Date addDateWeeks(Date date, int weeks) {
		DateTime dateTime = new DateTime(date);
		return dateTime.plusWeeks(weeks).toDate();
	}

	/**
	 * 对日期的【年】进行加/减
	 *
	 * @param date 日期
	 * @param years 年数，负数为减
	 * @return 加/减几年后的日期
	 */
	public static Date addDateYears(Date date, int years) {
		DateTime dateTime = new DateTime(date);
		return dateTime.plusYears(years).toDate();
	}

	public static int  getRemainingTime(Object lotteryTime){
		if(lotteryTime == null || StringUtils.isEmpty(lotteryTime.toString())){
			return 0;
		}
		int remainingTime = 0 ;
		SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);
		String newDate = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT).format(new Date());
		String lotteryTimeStr = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT).format(lotteryTime);
		try {
			Date date1 = format.parse(newDate);
			Date date2 = format.parse(lotteryTimeStr);
			remainingTime = (int) ((date2.getTime() - date1.getTime()+5000) / (1000));
			if(remainingTime < 0){
				remainingTime = 0;
			}
		} catch (ParseException e) {
			log.error("日期处理异常!");
		}
		return remainingTime;
	}
}
